//
//  GameModel.cpp
//  AtmKiller
//
//  Created by USoft on 6/5/14.
//
//

#include "GameModel.h"
static GameModel* sharedGameModel = NULL;
GameModel* GameModel::getInstance() {
    if (sharedGameModel == NULL) {
        sharedGameModel = new GameModel();
    }
    return sharedGameModel;
}

GameModel::GameModel() {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    AppUtils::setAdInvisible(true);
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    Application* application = Application::getInstance();
    application->openURL(":setBannerAdInvisible:");
#endif
    this->soundModel = SoundModel::getInstance();
    this->soundModel->setEffectsVolume(1);
    this->soundModel->setBackgroundMusicVolume(1);
    
    this->displayResolutionSize = Point::ZERO;
    this->vectorMove = Point::ZERO;
    this->currentSaveTime = CONF_SAVE_TIME;
    
    this->score = NULL;
    this->isPlayGame = false;
    this->numberOfNoti = 0;
    this->numberOfBonusNoti = 0;
    this->combo = Combo::create();
    CC_SAFE_RETAIN(this->combo);
    this->counter = Counter::create();
    CC_SAFE_RETAIN(this->counter);
    this->attacks = __Dictionary::create();
    CC_SAFE_RETAIN(this->attacks);
    this->ettRepository = EntityRepository::create();
    CC_SAFE_RETAIN(this->ettRepository);
    this->fingerInformation = FingerInformation::create();
    CC_SAFE_RETAIN(this->fingerInformation);
    this->finger = Finger::create();
    CC_SAFE_RETAIN(this->finger);
    this->atmInformation = AtmInformation::create();
    CC_SAFE_RETAIN(this->atmInformation);
    this->atm = Atm::create();
    CC_SAFE_RETAIN(this->atm);
    this->coins = __Array::create();
    CC_SAFE_RETAIN(this->coins);
    this->effects = __Array::create();
    CC_SAFE_RETAIN(this->effects);
    this->worldObjects = __Array::create();
    CC_SAFE_RETAIN(this->worldObjects);
    this->listeners = __Array::create();
    CC_SAFE_RETAIN(this->listeners);
    this->achievements = __Array::create();
    CC_SAFE_RETAIN(this->achievements);
    this->characters = __Dictionary::create();
    CC_SAFE_RETAIN(this->characters);
    
    this->loadCharacter();
    this->loadFinger();
    this->loadAtm();
    this->loadGame();
    this->loadDefault();
    this->loadCounter();
    this->loadAchievement();
    this->loadStatusAchievement();
}

GameModel::~GameModel() {
    Utils::safeRelease(this->combo);
    Utils::safeRelease(this->attacks);
    Utils::safeRelease(this->ettRepository);
    Utils::safeRelease(this->worldObjects);
    Utils::safeRelease(this->listeners);
    Utils::safeRelease(this->coins);
    Utils::safeRelease(this->characters);
    Utils::safeRelease(this->score);
    Utils::safeRelease(this->achievements);
}

void GameModel::initialize() {
    this->createWorld();
    this->createLand();
    this->play();
}

void GameModel::play() {
    this->gameState = GS_PLAY;
}

void GameModel::upgrade() {
    this->gameState = GS_UPGRADE;
}

void GameModel::update(float dt) {
    //update ads
    if(this->getGameState() == GS_PAUSE || this->getGameState() == GS_OPTION || this->getGameState() == GS_CONVERSION)
    {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        AppUtils::setAdInvisible(false);
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        Application* application = Application::getInstance();
        application->openURL(":setBannerAdVisible:");
#endif
        
    } else {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        AppUtils::setAdInvisible(true);
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        Application* application = Application::getInstance();
        application->openURL(":setBannerAdInvisible:");
#endif
    }
    
    //update sound
    {
        this->soundModel->update(dt);
    }
    // counter timePlay
    {
        this->counter->setTimePlay(this->counter->getTimePlay() + dt);
    }
    // counter timeSession
    {
        this->counter->setTimeSession(this->counter->getTimeSession() + dt);
    }
    // schedule save game
    {
        this->currentSaveTime -= dt;
        if (this->currentSaveTime < 0) {
            this->saveGame();
            this->saveCounter();
            this->currentSaveTime = CONF_SAVE_TIME;
        }
    }
    // update combo decrease
    {
        this->combo->update(dt);
    }
    // update character behavior
    {
        __Array* allKeys = this->getCharacters()->allKeys();
        if (allKeys != NULL) {
            for (int i = 0; i < allKeys->count(); i++) {
                __Integer* key = (__Integer*) allKeys->getObjectAtIndex(i);
                Character* character = (Character*) this->getCharacters()->objectForKey(key->getValue());
                EntityCharacter* entityCharacter = (EntityCharacter*)this->getEttRepository()->getCharacterList()->objectForKey(key->getValue());
                character->update(dt);
                
                // update attack
                if (character->getLevel() > 0) {
                    //init remainTimeToAttack and save to "attacks" directory
                    __Float* remainTimeToAttack = (__Float*) this->attacks->objectForKey(character->getCharacterId());
                    if (remainTimeToAttack == NULL) {
                        remainTimeToAttack = __Float::create(character->getAttackTime());
                    }
                    
                    float newRemainTimeToAttack = remainTimeToAttack->getValue() - dt;
                    // if the attacking time comes
                    if (newRemainTimeToAttack < 0) {
                        BigNumber *bigAttackTime = BigNumber::create();
                        bigAttackTime->initialize((int)character->getAttackTime());
                        BigNumber *scoreToAdd = bigAttackTime->complexMultiply(character->getDps());
                        this->createCoins(scoreToAdd, character->getCharacterId());
                        this->fireCharacterAttack(character);
                        newRemainTimeToAttack = character->getAttackTime();
                        
                    }
                    this->attacks->setObject(__Float::create(newRemainTimeToAttack), character->getCharacterId());
                }
                //update time to next upgrade
                if (character->getTimeToNextUpgrade() >= 0) {
                    character->setTimeToNextUpgrade(character->getTimeToNextUpgrade() - dt);
                }
                //update next upgrade available ?
                if (character->getUpgradeLevel() + 1 < entityCharacter->getAvatars()->count())
                {
                    EntityCharacterAvatar* avatar = (EntityCharacterAvatar*)entityCharacter->getAvatars()->getObjectAtIndex(character->getUpgradeLevel() + 1);
                    if (avatar->getRequiredLevel() <= character->getLevel() && character->getTimeToNextUpgrade() <= 0) {
                        character->setUpgradeAvailable(true);
                    } else {
                        character->setUpgradeAvailable(false);
                    }
                } else {
                    character->setUpgradeAvailable(false);
                }
                //characters'notification
                if(character->getLastNoti() != character->getUpgradeLevel() + 1 && character->getUpgradeAvailable() == true) {
                    character->setLastNoti(character->getUpgradeLevel() + 1);
                    this->fireShowNotification(character->getCharacterId());
                    character->setHasNoti(true);
                    
                }
            }
        }
    }
    //update behavior of finger
    {
        //update finger to next upgrade
        if (this->finger->getTimeToNextUpgrade() >= 0) {
            this->finger->setTimeToNextUpgrade(this->finger->getTimeToNextUpgrade() - dt);
        }
        
        //update next finger upgrade available ?
        if (this->finger->getUpgradeLevel() + 1 < this->fingerInformation->getUpgradeInfo()->count()) {
            FingerUpgrade* fingerUpgrade = (FingerUpgrade*)this->fingerInformation->getUpgradeInfo()->getObjectAtIndex(this->finger->getUpgradeLevel() + 1);
            if (fingerUpgrade->getRequiredLevel() <= this->finger->getLevel() && this->finger->getTimeToNextUpgrade() <= 0) {
                finger->setUpgradeAvailable(true);
            } else {
                finger->setUpgradeAvailable(false);
            }
        } else {
            finger->setUpgradeAvailable(false);
        }
        //update next finger bonus available ?
        if (this->finger->getBonusLevel() < this->fingerInformation->getBonusInfo()->count())
        {
            FingerBonus* fingerNextBonus = (FingerBonus*)this->fingerInformation->getBonusInfo()->getObjectAtIndex(this->finger->getBonusLevel());
            if(fingerNextBonus->getCondition()->compare(this->getCounter()->getTouchMoney()) <= 0) {
                this->finger->setBonusAvailable(true);
            } else {
                this->finger->setBonusAvailable(false);
            }
        } else {
            this->finger->setBonusAvailable(false);
        }
        //finger upgrade's notification
        if(this->finger->getLastNoti() != this->finger->getUpgradeLevel() + 1 && this->finger->getUpgradeAvailable() == true) {
            this->finger->setLastNoti(this->finger->getUpgradeLevel() + 1);
            this->fireShowNotification(CHAR_FINGER);
            this->finger->setHasNoti(true);
        }
        if(this->finger->getLastNotiBonus() != this->finger->getBonusLevel() + 1 && this->finger->getBonusAvailable() == true) {
            this->finger->setLastNotiBonus(this->finger->getBonusLevel() + 1);
            this->fireShowBonusNotification(CHAR_FINGER);
            this->finger->setHasNotiBonus(true);
        }
        
    }
    //update behavior of atm
    {
        //update next atm bonus available ?
        if (this->atm->getBonusLevel() + 1< this->atmInformation->getBonusInfo()->count())
        {
            AtmBonus* atmNextBonus = (AtmBonus*)this->atmInformation->getBonusInfo()->getObjectAtIndex(this->atm->getBonusLevel());
            if(atmNextBonus->getMoneyRequired()->compare(this->getCounter()->getTotalMoney()) <=0) {
                this->atm->setBonusAvailable(true);
            } else {
                this->atm->setBonusAvailable(false);
            }
        } else {
            this->atm->setBonusAvailable(false);
        }
        //atm bonus's notification
        if(this->atm->getLastNotiBonus() != this->atm->getBonusLevel() + 1 && this->atm->getBonusAvailable() == true) {
            this->atm->setLastNotiBonus(this->atm->getBonusLevel() + 1);
            //            this->fireShowBonusNotification(CHAR_ATM);
            this->fireShowNotification(CHAR_ATM);
            this->atm->setHasNotiBonus(true);
        }
    }
    // update total speed
    {
        BigNumber* totalSpeed = BigNumber::create();
        totalSpeed->initialize(0);
        {
            __Array* allKeys = this->getCharacters()->allKeys();
            if (allKeys != NULL) {
                for (int i = 0; i < allKeys->count(); i++) {
                    __Integer* key = (__Integer*) allKeys->getObjectAtIndex(i);
                    Character* character = (Character*) this->getCharacters()->objectForKey(key->getValue());
                    if (character->getLevel() > 0) {
                        
                        if (character->getCharacterId() == CHAR_GRANDMA) {
                            BigNumber* moneyGrandma = this->achievementEffect(character->getDps(), ACHIEVEMENT_EFFECT_GRANDMA);
                            //update moneyPerSec
                            moneyGrandma = this->bonusAtm(moneyGrandma);
                            moneyGrandma = this->achievementEffect(moneyGrandma, ACHIEVEMENT_EFFECT_DPS);
                            BigNumber* delMoneyPerSec = character->getMoneyPerSec();
                            character->setMoneyPerSec(moneyGrandma);
                            Utils::safeRelease(delMoneyPerSec);
                            CC_SAFE_RETAIN(character->getMoneyPerSec());
                            totalSpeed = totalSpeed->add(moneyGrandma);
                        } else if (character->getCharacterId() == CHAR_GAME_DEV){
                            BigNumber* moneyGameDev = this->achievementEffect(character->getDps(), ACHIEVEMENT_EFFECT_GAMEDEV);
                            //update moneyPerSec
                            moneyGameDev = this->bonusAtm(moneyGameDev);
                            moneyGameDev = this->achievementEffect(moneyGameDev, ACHIEVEMENT_EFFECT_DPS);
                            BigNumber* delMoneyPerSec = character->getMoneyPerSec();
                            character->setMoneyPerSec(moneyGameDev);
                            Utils::safeRelease(delMoneyPerSec);
                            CC_SAFE_RETAIN(character->getMoneyPerSec());
                            totalSpeed = totalSpeed->add(moneyGameDev);
                        } else {
                            BigNumber* moneyNormalChar = BigNumber::create();
                            moneyNormalChar->initialize(0);
                            moneyNormalChar = moneyNormalChar->add(character->getDps());
                            //update moneyPerSec
                            moneyNormalChar = this->bonusAtm(moneyNormalChar);
                            moneyNormalChar = this->achievementEffect(moneyNormalChar, ACHIEVEMENT_EFFECT_DPS);
                            BigNumber* delMoneyPerSec = character->getMoneyPerSec();
                            character->setMoneyPerSec(moneyNormalChar);
                            Utils::safeRelease(delMoneyPerSec);
                            CC_SAFE_RETAIN(character->getMoneyPerSec());
                            totalSpeed = totalSpeed->add(moneyNormalChar);
                        }
                    }
                }
            }
        }
        auto delTotalSpeed = this->counter->getTotalSpeed();
        this->counter->setTotalSpeed(totalSpeed);
        CC_SAFE_RETAIN(this->counter->getTotalSpeed());
        Utils::safeRelease(delTotalSpeed);
    }
    // update money per touch
    {
        BigNumber* bonusNumber = this->bonusFinger(this->counter->getTotalSpeed());
        BigNumber* moneyPerTouch = this->finger->getDpt()->add(bonusNumber);
        auto delMoneyPerTouch = this->counter->getMoneyPerTouch();
        this->counter->setMoneyPerTouch(moneyPerTouch);
        CC_SAFE_RETAIN(this->counter->getMoneyPerTouch());
        Utils::safeRelease(delMoneyPerTouch);
    }
    // update world
    {
        __Array* coinToDelete = __Array::create();
        this->world->Step(dt, 10, 10);
        for (unsigned int i = 0; i < this->worldObjects->count(); i++) {
            Coin* coin = dynamic_cast<Coin*>(this->worldObjects->getObjectAtIndex(i));
            if (coin != NULL) {
                coin->setExistingTime(coin->getExistingTime() - dt);
                // update position
                RectBody* coinBody = (RectBody*) coin->getBody();
                float x = coin->getWorldBody()->GetPosition().x;
                float y = coin->getWorldBody()->GetPosition().y;
                coinBody->setPosition(Point(WORLD_TO_SCREEN(x), WORLD_TO_SCREEN(y)));
                
                // update rotation
                coin->getWorldBody()->
                SetTransform(b2Vec2(SCREEN_TO_WORLD(coinBody->getPosition().x), SCREEN_TO_WORLD(coinBody->getPosition().y)), COCOS_ROTATION_TO_B2_ANGLE(coinBody->getRotation()));
                coin->update(dt);
                // remove coin
                if (WORLD_TO_SCREEN(coin->getWorldBody()->GetPosition().x) < -100 || WORLD_TO_SCREEN(coin->getWorldBody()->GetPosition().x) > displayResolutionSize.width) {
                    coinToDelete->addObject(coin);
                }
                
                if (coin->getExistingTime() < 2) {
                    Face* faceMainOfCoin = (Face*) coin->getFace((char*)FACE_MAIN);
                    Face* lightFace = (Face*) coin->getFace((char*)FACE_LIGHT);
                    if (faceMainOfCoin->getUserObject() == NULL) {
                        Action* action1 = faceMainOfCoin->getState(STATE_DISAPPEARED);
                        faceMainOfCoin->runAction(action1);
                        faceMainOfCoin->setUserObject(action1);
                        
                        Action* action2 = lightFace->getState(STATE_DISAPPEARED);
                        lightFace->runAction(action2);
                        lightFace->setUserObject(action2);
                    }
                }
                
                if (coin->getExistingTime() < 0) {
                    coinToDelete->addObject(coin);
                }
            }
        }
        //delete coins and free memory
        for (int i = 0; i < coinToDelete->count(); i++) {
            Coin* coin = (Coin*) coinToDelete->getObjectAtIndex(i);
            this->fireCoinsOut(coin);
            this->worldObjects->removeObject(coin);
            this->coins->removeObject(coin);
            this->world->DestroyBody(coin->getWorldBody());
        }
        
    }
    
    //update achievements
    this->setComparisonAchievement();
    this->examineAchievements();
    
    
    
}
void GameModel::createWorld() {
    b2Vec2 gravity = b2Vec2(0.0f, -50.0f);
    this->world = new b2World(gravity);
}

void GameModel::createCoins(BigNumber *amount,int coinFrom) {
    
    //calculate money to add
    BigNumber* moneyToAdd;
    //counter TouchMoney
    if(coinFrom == INDEX_COIN_FROM_TOUCHING){
        BigNumber* bonusNumber = this->bonusFinger(this->counter->getTotalSpeed());
        moneyToAdd = amount->add(bonusNumber);
        moneyToAdd = moneyToAdd->multiplyRationalNumber(this->combo->getCurrentComboInt());
        BigNumber* delTouchMoney = this->counter->getTouchMoney();
        this->counter->setTouchMoney(this->counter->getTouchMoney()->add(moneyToAdd));
        CC_SAFE_RETAIN(this->counter->getTouchMoney());
        Utils::safeRelease(delTouchMoney);
    }
    //counter characterMoney
    else {
        Character* character = (Character*) this->getCharacters()->objectForKey(coinFrom);
        
        moneyToAdd = amount;
        if(character->getCharacterId() == CHAR_GRANDMA) {
            moneyToAdd = this->achievementEffect(moneyToAdd, ACHIEVEMENT_EFFECT_GRANDMA);
        } else if (character->getCharacterId() == CHAR_GAME_DEV) {
            moneyToAdd = this->achievementEffect(moneyToAdd, ACHIEVEMENT_EFFECT_GAMEDEV);
        }
        moneyToAdd = this->bonusAtm(moneyToAdd);
        moneyToAdd = this->achievementEffect(moneyToAdd, ACHIEVEMENT_EFFECT_DPS);
        moneyToAdd = moneyToAdd->multiplyRationalNumber(this->combo->getCurrentComboInt());
        
        BigNumber* delCharacterMoney = character->getCharacterMoney();
        character->setCharacterMoney(character->getCharacterMoney()->add(moneyToAdd));
        Utils::safeRelease(delCharacterMoney);
        CC_SAFE_RETAIN(character->getCharacterMoney());
        
        BigNumber* delMoneyPerAtt = character->getMoneyPerAtt();
        character->setMoneyPerAtt(moneyToAdd);
        Utils::safeRelease(delMoneyPerAtt);
        CC_SAFE_RETAIN(character->getMoneyPerAtt());
        
        //counter upgradeLevelEarn
        BigNumber* upgradeLevelEarn = (BigNumber*)character->getUpgradeLevelEarn()->getObjectAtIndex(character->getUpgradeLevel());
        upgradeLevelEarn = upgradeLevelEarn->add(moneyToAdd);
        character->getUpgradeLevelEarn()->setObject(upgradeLevelEarn,character->getUpgradeLevel());
    }
    this->addMoney(moneyToAdd);
    //counter total Money
    auto delCounterMoney = this->counter->getTotalMoney();
    this->counter->setTotalMoney(this->counter->getTotalMoney()->add(moneyToAdd));
    CC_SAFE_RETAIN(this->counter->getTotalMoney());
    Utils::safeRelease(delCounterMoney);
    //kind of coin
    Coin* coin = Coin::create();
    {
        BigNumber* mark1 = BigNumber::create();
        mark1->initialize(10000);
        BigNumber* mark2 = BigNumber::create();
        mark2->initialize(100000);
        BigNumber* mark3 = BigNumber::create();
        mark3->initialize(1000000);
        BigNumber* mark4 = BigNumber::create();
        mark4->initialize(10000000);
        BigNumber* mark5 = BigNumber::create();
        mark5->initialize(100000000);
        BigNumber* mark6 = BigNumber::create();
        mark6->initialize(1000000000);
        BigNumber* mark7 = BigNumber::create();
        char* mark7Text = (char*)"10000000000";
        mark7->initialize(mark7Text);
        
        Face* mainFace = coin->getFace((char*)FACE_MAIN);
        Face* lightFace = coin->getFace((char*)FACE_LIGHT);
        if (moneyToAdd->compare(mark1) < 0) {
            mainFace->setSpriteFrame(ANI_COIN1);
            coin->setState((char*)STATE_COIN1, (char*)FACE_MAIN);
            coin->setGravity(5.0f);
        } else if (moneyToAdd->compare(mark2) < 0) {
            mainFace->setSpriteFrame(ANI_COIN2);
            coin->setState((char*)STATE_COIN2, (char*)FACE_MAIN);
            coin->setGravity(6.0f);
        } else if (moneyToAdd->compare(mark3) < 0) {
            mainFace->setSpriteFrame(ANI_COIN3);
            coin->setState((char*)STATE_COIN3, (char*)FACE_MAIN);
            coin->setGravity(7.0f);
        } else if (moneyToAdd->compare(mark4) < 0) {
            mainFace->setSpriteFrame(ANI_COIN4);
            coin->setState((char*)STATE_COIN4, (char*)FACE_MAIN);
            coin->setGravity(8.0f);
        } else if (moneyToAdd->compare(mark5) < 0) {
            mainFace->setSpriteFrame(ANI_COIN5);
            coin->setState((char*)STATE_COIN5, (char*)FACE_MAIN);
            coin->setGravity(9.0f);
        } else if (moneyToAdd->compare(mark6) < 0) {
            mainFace->setSpriteFrame(ANI_COIN6);
            coin->setState((char*)STATE_COIN6, (char*)FACE_MAIN);
            coin->setGravity(10.0f);
        } else if (moneyToAdd->compare(mark7) < 0) {
            lightFace->setSpriteFrame(ANI_COIN_LIGHT_7);
            mainFace->setSpriteFrame(ANI_COIN7);
            lightFace->setVisible(true);
            coin->setState((char*)STATE_COIN7, (char*)FACE_MAIN);
            coin->setGravity(11.0f);
        } else {
            lightFace->setSpriteFrame(ANI_COIN_LIGHT_8);
            mainFace->setSpriteFrame(ANI_COIN8);
            lightFace->setVisible(true);
            coin->setState((char*)STATE_COIN8, (char*)FACE_MAIN);
            coin->setGravity(12.0f);
        }
    }
    RectBody* coinBody = (RectBody*) coin->getBody();
    coin->setPosition(Point(ATM_X - 50 + Utils::random() * 100, ATM_Y - 50 + Utils::random() * 100));
    this->addToWorld(coinBody->getPosition(), Size(coinBody->getWidth(), coinBody->getHeight()), coin->getGravity(), 0.2f, 0.8f, coin);
    coin->appear();
    this->coins->addObject(coin);
    __Integer* characterIdInt = __Integer::create(coinFrom);
    this->fireCoinsAppear(coin,moneyToAdd, characterIdInt);
}


void GameModel::addMoney(BigNumber* moneyToAdd) {
    auto delScore = this->score;
    this->score = this->score->add(moneyToAdd);
    CC_SAFE_RETAIN(this->score);
    Utils::safeRelease(delScore);
}

void GameModel::subMoney(BigNumber* money) {
    auto delScore = this->score;
    this->score = this->score->minus(money);
    CC_SAFE_RETAIN(this->score);
    Utils::safeRelease(delScore);
}

void GameModel::handTouching() {
    this->createCoins(this->finger->getDpt(),INDEX_COIN_FROM_TOUCHING);
    this->combo->raise(0.1f);
    //counter TouchNumbers
    BigNumber* touchNumbers = this->counter->getTouchNumbers();
    this->counter->setTouchNumbers(this->counter->getTouchNumbers()->add(1));
    CC_SAFE_RETAIN(this->counter->getTouchNumbers());
    Utils::safeRelease(touchNumbers);
    
    if(this->counter->getTouchNumbers()->isDivisible2000() == true) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        AppUtils::showAdFullscreen();
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        Application* application = Application::getInstance();
        application->openURL(":setFullAdVisible:");
#endif
    }
    
}

void GameModel::createLand() {
    b2BodyDef groundBodyDef;
    groundBodyDef.position.Set(0,0);
    b2Body* groundBody = this->world->CreateBody(&groundBodyDef);
    
    b2EdgeShape groundEdge;
    groundEdge.Set(b2Vec2(-100 / PTM_RATIO, GROUND_Y / PTM_RATIO), b2Vec2(this->displayResolutionSize.width / PTM_RATIO, GROUND_Y / PTM_RATIO));
    groundBody->CreateFixture(&groundEdge, 0);
    b2Fixture* bodyFixture = groundBody->GetFixtureList();
    b2Filter* bodyFilter = new b2Filter();
    bodyFilter->categoryBits = 0x0002;
    bodyFilter->maskBits = 0x0001;
    bodyFixture->SetFilterData(*bodyFilter);
}

void GameModel::addListener(UGListener* listener) {
    if (this->listeners != NULL) {
        this->listeners->addObject(listener);
    }
}

void GameModel::effectAppear(Point point) {
    if(this->finger->getUpgradeLevel() > 0){
        FingerEffect* effect = FingerEffect::create();
        Face* mainFace = effect->getFace((char*)FACE_MAIN);
        if(this->finger->getUpgradeLevel() <= 2){
            mainFace->setSpriteFrame(ANI_EFFECT0);
            effect->setState((char*)STATE_EFFECT0, (char*)FACE_MAIN);
        } else if(this->finger->getUpgradeLevel() <= 4) {
            mainFace->setSpriteFrame(ANI_EFFECT1);
            effect->setState((char*)STATE_EFFECT1, (char*)FACE_MAIN);
        } else if(this->finger->getUpgradeLevel() <= 6) {
            mainFace->setSpriteFrame(ANI_EFFECT2);
            effect->setState((char*)STATE_EFFECT2, (char*)FACE_MAIN);
        } else if(this->finger->getUpgradeLevel() <= 8) {
            mainFace->setSpriteFrame(ANI_EFFECT3);
            effect->setState((char*)STATE_EFFECT3, (char*)FACE_MAIN);
        } else if(this->finger->getUpgradeLevel() <= 10) {
            mainFace->setSpriteFrame(ANI_EFFECT4);
            effect->setState((char*)STATE_EFFECT4, (char*)FACE_MAIN);
        } else if(this->finger->getUpgradeLevel() <= 12) {
            mainFace->setSpriteFrame(ANI_EFFECT5);
            effect->setState((char*)STATE_EFFECT5, (char*)FACE_MAIN);
        }
        effect->setPosition(point);
        this->fireEffectAppear(effect);
    }
}
bool GameModel::isAtmTouchable() {
    if (this->gameState == GS_PLAY) {
        return true;
    }
    return false;
}

bool GameModel::isCharacterTouchable() {
    if (this->gameState == GS_UPGRADE) {
        return true;
    }
    return false;
}

void GameModel::addToWorld(cocos2d::Point position, cocos2d::Size size, float density, float friction, float restitution, WorldObj *obj) {
    // bodyDef
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(position.x / PTM_RATIO, position.y / PTM_RATIO);
    b2Body* body = this->world->CreateBody(&bodyDef);
    
    // setBody
    obj->setWorldBody(body);
    
    // fixtureDef
    b2PolygonShape polygonShape;
    polygonShape.SetAsBox(size.width / 2 / PTM_RATIO, size.height / 2 / PTM_RATIO);
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &polygonShape;
    fixtureDef.density = density;
    fixtureDef.friction = friction;
    fixtureDef.restitution = restitution;
    fixtureDef.filter.categoryBits = 0x0001;
    fixtureDef.filter.maskBits = 0x0002;
    b2Fixture* fixture = body->CreateFixture(&fixtureDef);
    
    // setFixture
    obj->setFixture(fixture);
    this->worldObjects->addObject(obj);
}
void GameModel::fireEffectAppear(FingerEffect *effect){
    if (this->listeners != NULL) {
        __Dictionary* dictionary = CCDictionary::create();
        dictionary->setObject(effect, "effect");
        
        for (int i = 0; i < this->listeners->count(); i++) {
            GameListener* listener = dynamic_cast<GameListener*> (this->listeners->getObjectAtIndex(i));
            if (listener != NULL ) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getEffectAppear();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(dictionary);
                }
            }
        }
    }
}
void GameModel::fireCoinsAppear(Coin *coin, BigNumber * amount, __Integer* id) {
    this->soundModel->playEffect(EF_COIN, false, 0.0f);
    if (this->listeners != NULL) {
        __Dictionary* dictionary = CCDictionary::create();
        dictionary->setObject(coin, "coin");
        dictionary->setObject(amount, "amount");
        dictionary->setObject(id, "id");
        
        for (int i = 0; i < this->listeners->count(); i++) {
            GameListener* listener = dynamic_cast<GameListener*> (this->listeners->getObjectAtIndex(i));
            if (listener != NULL ) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getCoinAppear();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(dictionary);
                }
            }
        }
    }
}

void GameModel::fireCoinsOut(Coin *coin) {
    if (this->listeners != NULL) {
        __Dictionary* dictionary = CCDictionary::create();
        dictionary->setObject(coin, "coin");
        for (int i = 0; i < this->listeners->count(); i++) {
            GameListener* listener = dynamic_cast<GameListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getCoinOut();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(dictionary);
                }
            }
        }
    }
}

void GameModel::fireCharacterAttack(Character* character) {
    if (this->listeners != NULL) {
        __Dictionary* dictionary = CCDictionary::create();
        dictionary->setObject(character, "character");
        for (int i = 0; i < this->listeners->count(); i++) {
            GameListener* listener = dynamic_cast<GameListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getCharacterAttack();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(dictionary);
                }
            }
        }
    }
}

void GameModel::fireUpgradeAtmFace() {
    if (this->listeners != NULL) {
        for (int i = 0; i < this->listeners->count(); i++) {
            GameListener* listener = dynamic_cast<GameListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getUpgradeAtmFace();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
                
            }
        }
    }
}

void GameModel::fireShowNotification(int characterId) {
    this->numberOfNoti += 1;
    this->soundModel->playEffect(EF_NOTI, false, 0.0f);
    __Integer *idInteger = __Integer::create(characterId);
    if (this->listeners != NULL) {
        for (int i = 0;i < this->listeners->count(); i++){
            NotificationListener* listener = dynamic_cast<NotificationListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getShowNotification();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(idInteger);
                }
            }
        }
    }
}

void GameModel::fireRemoveNotification(int characterId) {
    this->numberOfNoti -= 1;
    __Integer *idInteger = __Integer::create(characterId);
    if (this->listeners != NULL) {
        for (int i = 0;i < this->listeners->count(); i++){
            NotificationListener* listener = dynamic_cast<NotificationListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getRemoveNotification();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(idInteger);
                }
            }
        }
    }
}

void GameModel::fireShowBonusNotification(int characterId) {
    this->numberOfBonusNoti += 1;
    __Integer *idInteger = __Integer::create(characterId);
    if (this->listeners != NULL) {
        for (int i = 0;i < this->listeners->count(); i++){
            NotificationListener* listener = dynamic_cast<NotificationListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getShowBonusNotification();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(idInteger);
                }
            }
        }
    }
    
}

void GameModel::fireRemoveBonusNotification(int characterId) {
    this->numberOfBonusNoti -= 1;
    __Integer *idInteger = __Integer::create(characterId);
    if (this->listeners != NULL) {
        for (int i = 0;i < this->listeners->count(); i++){
            NotificationListener* listener = dynamic_cast<NotificationListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getRemoveBonusNotification();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(idInteger);
                }
            }
        }
    }
    
}

void GameModel::fireChangeCharacter(){
    if (this->listeners != NULL) {
        for (int i = 0; i < this->listeners->count(); i++) {
            UpgradeListener* listener = dynamic_cast<UpgradeListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getChangeCharacter();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}


void GameModel::fireChangeAvatarShopping(){
    if (this->listeners != NULL) {
        for (int i = 0; i < this->listeners->count(); i++) {
            ShoppingListener* listener = dynamic_cast<ShoppingListener*> (this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getChangeCharacter();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}


void GameModel::fireShowAchievementNoti(int achievementId) {
    this->soundModel->playEffect(EF_ACHI, false, 0.0f);
    __Integer *idInteger = __Integer::create(achievementId);
    if (this->listeners != NULL) {
        for (int i = 0; i < this->listeners->count(); i++) {
            GUIListener* listener = dynamic_cast<GUIListener* >(this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getShowAchievementNoti();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(idInteger);
                }
            }
        }
    }
}

void GameModel::loadCharacter() {
    Json* root;
    string fileData = Utils::readFile(DOC_CHARACTER, false, true, true);// read file characters.dat
    root = Json_create(fileData.data());
    
    if (root) {
        Json* characters = Json_getItem(root, "characters");
        int characterSize = characters->size;
        for (int i = 0; i < characterSize; i++) {
            //get information from json
            Json* character = Json_getItemAt(characters, i);
            int characterId = Json_getInt(character, "characterId", 0);
            int maxLevel = Json_getInt(character, "maxLevel", 0);
            string name = Json_getString(character, "name", "");
            string avatarImage = Json_getString(character, "avatar", "");
            BigNumber *cost = BigNumber::create();
            cost->initialize(Json_getString(character, "cost", "0"));
            double attackTime =  atof(Json_getString(character, "attackTime", "0"));
            BigNumber *dps = BigNumber::create();
            dps->initialize(Json_getString(character, "dps", "0"));
            
            //add information to a ettCharacter variable.
            EntityCharacter* ettCharacter = EntityCharacter::create();
            ettCharacter->setCharacterId(characterId);
            ettCharacter->setMaxLevel(maxLevel);
            ettCharacter->setName(name);
            ettCharacter->setAvatarImage(avatarImage);
            ettCharacter->setCost(cost);
            CC_SAFE_RETAIN(ettCharacter->getCost());
            ettCharacter->setAttackTime(attackTime);
            ettCharacter->setDps(dps);
            CC_SAFE_RETAIN(ettCharacter->getDps());
            
            Json* avatars = Json_getItem(character, "avatars");
            int avatarSize = avatars->size;
            for (int j = 0; j < avatarSize; j++) {
                Json* avatar = Json_getItemAt(avatars, j);
                string caption = Json_getString(avatar, "caption", "");
                string upgradeAvatar = Json_getString(avatar, "upgradeAvatar", "");
                string description = Json_getString(avatar, "description", "");
                float timeWaiting = Json_getFloat(avatar, "timeWaiting", 0);
                string effect = Json_getString(avatar, "effect", "");
                BigNumber* addingUnit = BigNumber::create();
                addingUnit->initialize(Json_getString(avatar,"addingUnit","0"));
                int mulUnit = Json_getInt(avatar,"mulUnit",1);
                string requiredString = Json_getString(avatar, "requiredString", "");
                BigNumber *price = BigNumber::create();
                price->initialize(Json_getString(avatar, "price", "0"));
                
                Json* required = Json_getItem(avatar, "required");
                int level = Json_getInt(required, "level", 0);
                
                EntityCharacterAvatar* ettCharacterAvatar = EntityCharacterAvatar::create();
                ettCharacterAvatar->setCaption(caption);
                ettCharacterAvatar->setUpgradeAvatar(upgradeAvatar);
                ettCharacterAvatar->setDescription(description);
                ettCharacterAvatar->setTimeWaiting(timeWaiting * 60);
                ettCharacterAvatar->setEffect(effect);
                ettCharacterAvatar->setRequiredString(requiredString);
                ettCharacterAvatar->setPrice(price);
                CC_SAFE_RETAIN(ettCharacterAvatar->getPrice());
                ettCharacterAvatar->setAddingUnit(addingUnit);
                CC_SAFE_RETAIN(ettCharacterAvatar->getAddingUnit());
                ettCharacterAvatar->setMulUnit(mulUnit);
                ettCharacterAvatar->setRequiredLevel(level);
                
                ettCharacter->getAvatars()->addObject(ettCharacterAvatar);
            }
            //add ettCharacter into ettRepository
            this->ettRepository->getCharacterList()->setObject(ettCharacter, characterId);
        }
    } else {
        CCLOG("Failed to parse JSON");
    }
    Json_dispose(root);
}

void GameModel::loadFinger(){
    Json* root;
    string fileData = Utils::readFile(DOC_FINGER,false,true,true);
    root = Json_create(fileData.data());
    if(root) {
        Json* fingers = Json_getItem(root, "fingers");
        Json* information = Json_getItemAt(fingers,0);
        BigNumber* baseDpt = BigNumber::create();
        string a = Json_getString(information,"baseDpt","");
        baseDpt->initialize(Json_getString(information,"baseDpt",""));
        BigNumber* baseCost = BigNumber::create();
        baseCost->initialize(Json_getString(information,"baseCost",""));
        string avatarImage = Json_getString(information,"avatar","");
        //set base Cost
        this->fingerInformation->setBaseCost(baseCost);
        CC_SAFE_RETAIN(this->fingerInformation->getBaseCost());
        //set base Dpt
        this->fingerInformation->setBaseDpt(baseDpt);
        CC_SAFE_RETAIN(this->fingerInformation->getBaseDpt());
        //set avatar
        this->fingerInformation->setAvatarImage(avatarImage);
        //set array of upgraded information
        Json* upgradeInfo = Json_getItem(information,"fingerUpgrade");
        int infoSize = upgradeInfo->size;
        for(int i=0;i<infoSize;i++)
        {
            //get Information from Json file
            Json* info = Json_getItemAt(upgradeInfo, i);
            int requiredlevel = Json_getInt(info,"level",0);
            float timeWaiting = Json_getFloat(info, "timeWaiting", 0);
            string name = Json_getString(info,"name","");
            string upgradeAvatar = Json_getString(info, "upgradeAvatar", "");
            string description = Json_getString(info,"description","");
            string requiredString = Json_getString(info,"requiredString","");
            string effect = Json_getString(info,"effect","");
            BigNumber* price = BigNumber::create();
            price->initialize(Json_getString(info, "price","0"));
            //set value for fingerUpdate
            FingerUpgrade* fingerUpgrade = FingerUpgrade::create();
            fingerUpgrade->setUpgradeAvatar(upgradeAvatar);
            fingerUpgrade->setDescription(description);
            fingerUpgrade->setEffect(effect);
            fingerUpgrade->setTimeWaiting(timeWaiting * 60);
            fingerUpgrade->setName(name);
            fingerUpgrade->setPrice(price);
            CC_SAFE_RETAIN(fingerUpgrade->getPrice());
            fingerUpgrade->setRequiredLevel(requiredlevel);
            fingerUpgrade->setRequiredString(requiredString);
            //add to array upgradeInfo of finger Information
            this->fingerInformation->getUpgradeInfo()->addObject(fingerUpgrade);
        }
        //set array of bonus information
        Json* bonusInfo = Json_getItem(information,"fingerBonus");
        int bonusSize = bonusInfo->size;
        for(int i=0;i<bonusSize;i++)
        {
            Json* info = Json_getItemAt(bonusInfo, i);
            int bonusId = Json_getInt(info,"bonusId", 0);
            string name = Json_getString(info,"name","");
            string bonusAvatar = Json_getString(info, "bonusAvatar", "");
            string effect = Json_getString(info, "effect", "");
            string description = Json_getString(info, "description", "");
            float percent = Json_getFloat(info, "percent", 0.0f);
            BigNumber* price = BigNumber::create();
            price->initialize(Json_getString(info,"price","0"));
            BigNumber* condition = BigNumber::create();
            condition->initialize(Json_getString(info,"condition","0"));
            //set value for fingerBonus
            FingerBonus* fingerBonus = FingerBonus::create();
            fingerBonus->setBonusId(bonusId);
            fingerBonus->setName(name);
            fingerBonus->setBonusAvatar(bonusAvatar);
            fingerBonus->setEffect(effect);
            fingerBonus->setDescription(description);
            fingerBonus->setPercent(percent);
            fingerBonus->setCondition(condition);
            CC_SAFE_RETAIN(fingerBonus->getCondition());
            fingerBonus->setPrice(price);
            CC_SAFE_RETAIN(fingerBonus->getPrice());
            this->fingerInformation->getBonusInfo()->addObject(fingerBonus);
        }
    }
    else {
        CCLOG("Failed to parse FINGER JSON");
    }
    Json_dispose(root);
}

void GameModel::loadAtm() {
    Json* root;
    string fileData = Utils::readFile(DOC_ATM, false, true, true);
    root = Json_create(fileData.data());
    if (root) {
        Json* atm = Json_getItem(root,"atm");
        Json* information = Json_getItemAt(atm, 0);
        string atmAvatar = Json_getString(information, "atmAvatar", "");
        Json* atmBonus = Json_getItem(information, "atmBonus");
        this->atmInformation->setAvatarImage(atmAvatar);
        int bonusSize = atmBonus->size;
        for (int i = 0; i < bonusSize; i++) {
            Json* bonusInfo = Json_getItemAt(atmBonus , i);
            int bonusId = Json_getInt(bonusInfo, "bonusId", 0);
            std::string bonusAvatar = Json_getString(bonusInfo, "bonusAvatar", "");
            std::string bonusFace = Json_getString(bonusInfo, "bonusFace", "");
            std::string name = Json_getString(bonusInfo, "name", "");
            std::string effect = Json_getString(bonusInfo, "effect", "");
            std::string description = Json_getString(bonusInfo, "description", "");
            int multiplierPercent = Json_getInt(bonusInfo, "multiplierPercent", 0);
            BigNumber* price = BigNumber::create();
            price->initialize(Json_getString(bonusInfo, "price", "0"));
            
            BigNumber* moneyRequired = BigNumber::create();
            moneyRequired->initialize(Json_getString(bonusInfo, "moneyRequired", "0"));
            AtmBonus* atmBonus = AtmBonus::create();
            atmBonus->setBonusId(bonusId);
            atmBonus->setBonusAvatar(bonusAvatar);
            atmBonus->setBonusFace(bonusFace);
            atmBonus->setName(name);
            atmBonus->setEffect(effect);
            atmBonus->setDescription(description);
            atmBonus->setMultiplierPercent(multiplierPercent);
            atmBonus->setPrice(price);
            CC_SAFE_RETAIN(atmBonus->getPrice());
            atmBonus->setMoneyRequired(moneyRequired);
            CC_SAFE_RETAIN(atmBonus->getMoneyRequired());
            this->atmInformation->getBonusInfo()->addObject(atmBonus);
        }
    } else {
        CCLOG("Failed to parse ATM JSON");
    }
    Json_dispose(root);
}
void GameModel::loadGame() {
    //load current Characters
    Json* root;
    string fileData = Utils::readFile(DOC_USER, true, false, true);
    root = Json_create(fileData.data());
    
    if (root) {
        this->isPlayGame = true;
        Json* characters = Json_getItem(root, "characters");
        int characterSize = characters->size;
        for (int i = 0; i < characterSize; i++) {
            //get Json file
            Json* character = Json_getItemAt(characters, i);
            int characterId = Json_getInt(character, "characterId", 0);
            int level = Json_getInt(character, "level", 0);
            float timeUpgrade = Json_getFloat(character, "timeToNextUpgrade", 0);
            int upgradeLevel = Json_getInt(character, "upgrade-level", 0);
            BigNumber* characterMoney = BigNumber::create();
            characterMoney->initialize(Json_getString(character,"characterMoney","0"));
            
            BigNumber* moneyPerSec = BigNumber::create();
            moneyPerSec->initialize(0);
            
            BigNumber* moneyPerAtt = BigNumber::create();
            moneyPerAtt->initialize(0);
            Json* upgradeLvlEarn = Json_getItem(character,"upgradeLvlEarn");
            
            EntityCharacter* entityCharacter = (EntityCharacter*) this->ettRepository->getCharacterList()->objectForKey(characterId);
            //create character
            Character* c = Character::create();
            c->initCharacter(entityCharacter->getCharacterId(),upgradeLevel);
            c->initUpgradeLevel((int)entityCharacter->getAvatars()->count());
            for(int j=0;j<upgradeLvlEarn->size;j++)
            {
                Json* element = Json_getItemAt(upgradeLvlEarn,j);
                string a = element->valueString;
                BigNumber* moneyEarn = BigNumber::create();
                moneyEarn->initialize(a.c_str());
                c->getUpgradeLevelEarn()->setObject(moneyEarn, j);
            }
            //  c->initUpgradeLevel((int)entityCharacter->getAvatars()->count());
            c->setName(entityCharacter->getName());
            c->setTimeToNextUpgrade(timeUpgrade);
            c->upLevel(entityCharacter, level,upgradeLevel);
            c->setUpgradeLevel(upgradeLevel);
            c->setCharacterMoney(characterMoney);
            CC_SAFE_RETAIN(c->getCharacterMoney());
            c->setMoneyPerSec(moneyPerSec);
            CC_SAFE_RETAIN(c->getMoneyPerSec());
            c->setMoneyPerAtt(moneyPerAtt);
            CC_SAFE_RETAIN(c->getMoneyPerAtt());
            
            this->characters->setObject(c, c->getCharacterId());
        }
        
        this->score = BigNumber::create();
        this->score->initialize(Json_getString(root, "money", "0"));
        CC_SAFE_RETAIN(this->score);
        
        this->finger->setLevel(Json_getInt(root,"fingerLevel",1));
        this->finger->setUpgradeLevel(Json_getInt(root,"fingerUpgradeLevel",0));
        this->finger->setBonusLevel(Json_getInt(root,"fingerBonusLevel",0));
        this->finger->setTimeToNextUpgrade(Json_getFloat(root, "fingerNextUpgrade", 0));
        this->finger->upLevel(this->fingerInformation,this->finger->getLevel(),this->finger->getUpgradeLevel(),this->getTotalCharactersLevel());
        
        this->atm->setBonusLevel(Json_getInt(root,"atmBonusLevel",0));
    } else {
        //init score
        this->score = BigNumber::create();
        this->score->initialize(0);
        CC_SAFE_RETAIN(this->score);
        //init finger
        FingerInformation* fingerInfo = this->getFingerInformation();
        FingerUpgrade* fingerUpgrade = (FingerUpgrade*) fingerInfo->getUpgradeInfo()->getObjectAtIndex(0);
        this->finger->setLevel(1);
        this->finger->setUpgradeLevel(0);
        this->finger->setBonusLevel(0);
        this->finger->upLevel(this->fingerInformation,this->finger->getLevel(),this->finger->getUpgradeLevel(),this->getTotalCharactersLevel());
        this->finger->setTimeToNextUpgrade(fingerUpgrade->getTimeWaiting());
        
        this->atm->setBonusLevel(0);
        CCLOG("Failed to parse JSON");
    }
    Json_dispose(root);
    
}

void GameModel::loadDefault() {
    {
        __Array* ids = __Array::create();
        ids->addObject(__Integer::create(CHAR_CEO));
        ids->addObject(__Integer::create(CHAR_GHOST));
        ids->addObject(__Integer::create(CHAR_GOD));
        ids->addObject(__Integer::create(CHAR_GOVERMENT));
        ids->addObject(__Integer::create(CHAR_GRANDMA));
        ids->addObject(__Integer::create(CHAR_HACKER));
        ids->addObject(__Integer::create(CHAR_KID));
        ids->addObject(__Integer::create(CHAR_SUPER_MAN));
        ids->addObject(__Integer::create(CHAR_GAME_DEV));
        
        for (int i = 0; i < ids->count(); i++) {
            __Integer* id = (__Integer*) ids->getObjectAtIndex(i);
            Character* c = (Character*) this->characters->objectForKey(id->getValue());
            if (c == NULL) {
                EntityCharacter* entityCharacter = (EntityCharacter*) this->ettRepository->getCharacterList()->objectForKey(id->getValue());
                c = Character::create();
                c->initCharacter(entityCharacter->getCharacterId(),0);
                c->initUpgradeLevel((int)entityCharacter->getAvatars()->count());
                c->setName(entityCharacter->getName());
                
                BigNumber* characterMoney = BigNumber::create();
                characterMoney->initialize(0);
                
                BigNumber* moneyPerSec = BigNumber::create();
                moneyPerSec->initialize(0);
                
                BigNumber* moneyPerAtt = BigNumber::create();
                moneyPerAtt->initialize(0);
                
                c->setCharacterMoney(characterMoney);
                CC_SAFE_RETAIN(c->getCharacterMoney());
                c->setMoneyPerSec(moneyPerSec);
                CC_SAFE_RETAIN(c->getMoneyPerSec());
                c->setMoneyPerAtt(moneyPerAtt);
                CC_SAFE_RETAIN(c->getMoneyPerAtt());
                
                c->upLevel(entityCharacter, 0,0);
                this->characters->setObject(c, c->getCharacterId());
            }
        }
    }
}

void GameModel::loadCounter() {
    Json* root;
    string fileData = Utils::readFile(DOC_COUNTER,true,false,true);
    root = Json_create(fileData.data());
    if(root){
        BigNumber* totalMoney = BigNumber::create();
        totalMoney->initialize(Json_getString(root,"totalMoney",0));
        
        BigNumber* touchNumbers = BigNumber::create();
        touchNumbers->initialize(Json_getString(root,"touchNumbers",0));
        
        float timePlay = Json_getFloat(root,"timePlay",0);
        
        BigNumber* touchMoney = BigNumber::create();
        touchMoney->initialize(Json_getString(root,"touchMoney",0));
        
        this->counter->setTotalMoney(totalMoney);
        CC_SAFE_RETAIN(this->counter->getTotalMoney());
        
        this->counter->setTouchNumbers(touchNumbers);
        CC_SAFE_RETAIN(this->counter->getTouchNumbers());
        
        this->counter->setTimePlay(timePlay);
        
        this->counter->setTimeSession(0);
        
        this->counter->setTouchMoney(touchMoney);
        CC_SAFE_RETAIN(this->counter->getTouchMoney());
        
        Json_dispose(root);
    }
    else{
        //set default if can't read json file
        //totalMoney = 0
        BigNumber* totalMoney = BigNumber::create();
        totalMoney->initialize(0);
        //touchNumbers = 0
        BigNumber* touchNumbers = BigNumber::create();
        touchNumbers->initialize(0);
        
        float timePlay = 0;
        float timeSession = 0;
        //touchMoney = 0
        BigNumber* touchMoney = BigNumber::create();
        touchMoney->initialize(0);
        
        this->counter->setTotalMoney(totalMoney);
        CC_SAFE_RETAIN(this->counter->getTotalMoney());
        
        this->counter->setTouchNumbers(touchNumbers);
        CC_SAFE_RETAIN(this->counter->getTouchNumbers());
        
        this->counter->setTouchMoney(touchMoney);
        CC_SAFE_RETAIN(this->counter->getTouchMoney());
        
        this->counter->setTimePlay(timePlay);
        this->counter->setTimeSession(timeSession);
        
    }
}

void GameModel::loadAchievement() {
    Json* root;
    string fileData = Utils::readFile(DOC_ACHIEVEMENT, false, true, true);
    root = Json_create(fileData.data());
    if(root){
        Json* achievements = Json_getItem(root,"achievement");
        int achievementSize = achievements->size;
        for(int i=0;i<achievementSize;i++) {
            //get Json file
            Json* achievement = Json_getItemAt(achievements, i);
            int achievementId = Json_getInt(achievement, "achievementID", 0);
            string name = Json_getString(achievement, "name", "");
            string description = Json_getString(achievement, "description", 0);
            int type = Json_getInt(achievement, "type", 0);
            int effectType = Json_getInt(achievement, "effectType", 0);
            float effectPercent = Json_getFloat(achievement, "effectPercent", 0);
            
            if (type == ACHIEVEMENT_TYPE_MONEY){
                BigNumber* objective = BigNumber::create();
                objective->initialize(Json_getString(achievement,"objective","0"));
                MoneyAchievement* moneyAchievement = MoneyAchievement::create();
                moneyAchievement->setAchievementID(achievementId);
                moneyAchievement->setName(name);
                moneyAchievement->setType(type);
                moneyAchievement->setDescription(description);
                moneyAchievement->setObjective(objective);
                moneyAchievement->setEffectType(effectType);
                moneyAchievement->setEffectPercent(effectPercent);
                CC_SAFE_RETAIN(moneyAchievement->getObjective());
                moneyAchievement->getFace()->initWithSpriteFrameName(ANI_ACHIEVEMENT_LOCK_1);
                
                this->achievements->addObject(moneyAchievement);
            } else if (type == ACHIEVEMENT_TYPE_LEVEL) {
                int objective = Json_getInt(achievement, "objective",0);
                LevelAchievement* levelAchievement = LevelAchievement::create();
                levelAchievement->setAchievementID(achievementId);
                levelAchievement->setName(name);
                levelAchievement->setType(type);
                levelAchievement->setDescription(description);
                levelAchievement->setObjective(objective);
                levelAchievement->setEffectPercent(effectPercent);
                levelAchievement->setEffectType(effectType);
                levelAchievement->getFace()->initWithSpriteFrameName(ANI_ACHIEVEMENT_LOCK_1);
                this->achievements->addObject(levelAchievement);
            } else if (type == ACHIEVEMENT_TYPE_OTHER) {
                int objective = Json_getInt(achievement, "objective",0);
                OtherAchievement* otherAchievement = OtherAchievement::create();
                otherAchievement->setAchievementID(achievementId);
                otherAchievement->setName(name);
                otherAchievement->setType(type);
                otherAchievement->setDescription(description);
                otherAchievement->setObjective(objective);
                otherAchievement->setEffectType(effectType);
                otherAchievement->setEffectPercent(effectPercent);
                otherAchievement->getFace()->initWithSpriteFrameName(ANI_ACHIEVEMENT_LOCK_1);
                this->achievements->addObject(otherAchievement);
            }
        }
    }
    Json_dispose(root);
}

void GameModel::saveGame() {
    string userStr;
    string userCharacterStr = "";
    
    __Array* allKeys = this->getCharacters()->allKeys();
    if (allKeys != NULL) {
        for (int i = 0; i < allKeys->count(); i++) {
            __Integer* key = (__Integer*) allKeys->getObjectAtIndex(i);
            Character* character = (Character*) this->getCharacters()->objectForKey(key->getValue());
            char jsonContent[1000];
            char* delMoneyString = character->getCharacterMoney()->toString();
            sprintf(jsonContent, TXT_USER_CHARACTER_JSON, character->getCharacterId(), character->getLevel(), character->getTimeToNextUpgrade(), character->getUpgradeLevel(),delMoneyString);
            delete[] delMoneyString;
            userCharacterStr.append(jsonContent);
            userCharacterStr.append(",\"upgradeLvlEarn\":[");
            for(int j=0;j<character->getUpgradeLevelEarn()->count();j++)
            {
                BigNumber* temp = (BigNumber*)character->getUpgradeLevelEarn()->getObjectAtIndex(j);
                char upgradeLvlEarnStr[100];
                char* tempString = temp->toString();
                sprintf(upgradeLvlEarnStr,"\"%s\"", tempString);
                delete[] tempString;
                userCharacterStr.append(upgradeLvlEarnStr);
                if(j!= character->getUpgradeLevelEarn()->count()-1){
                    userCharacterStr.append(",");
                }
            }
            userCharacterStr.append("]}");
            if (i != allKeys->count() - 1) {
                userCharacterStr.append(",");
            }
        }
    }
    
    char moneyStr[200];
    char fingerNextUpgrade[10];
    char fingerLevelStr[10];
    char fingerUpgradeLevelStr[10];
    char fingerBonusLevel[10];
    char atmBonusLevel[10];
    sprintf(fingerNextUpgrade, "%f", this->finger->getTimeToNextUpgrade());
    sprintf(fingerLevelStr,"%d", this->finger->getLevel());
    sprintf(fingerUpgradeLevelStr, "%d", this->finger->getUpgradeLevel());
    sprintf(fingerBonusLevel, "%d", this->finger->getBonusLevel());
    sprintf(atmBonusLevel,"%d", this->atm->getBonusLevel());
    
    char* scoreString = this->score->toString();
    sprintf(moneyStr, "%s", scoreString);
    delete[] scoreString;
    
    userStr.append("{\"characters\":[");
    userStr.append(userCharacterStr);
    userStr.append("], \"money\": \"");
    userStr.append(moneyStr);
    userStr.append("\", \"fingerLevel\": ");
    userStr.append(fingerLevelStr);
    userStr.append(", \"fingerNextUpgrade\": ");
    userStr.append(fingerNextUpgrade);
    userStr.append(", \"fingerUpgradeLevel\": ");
    userStr.append(fingerUpgradeLevelStr);
    userStr.append(", \"fingerBonusLevel\": ");
    userStr.append(fingerBonusLevel);
    userStr.append(", \"atmBonusLevel\": ");
    userStr.append(atmBonusLevel);
    userStr.append("}");
    
    
    Utils::writeFile(userStr, DOC_USER, true);
}

void GameModel::saveCounter() {
    string counterStr;
    char totalMoneyStr[200];
    char touchNumbersStr[200];
    char touchMoneyStr[200];
    char timePlayStr[200];
    
    char* deltotalMoney = this->counter->getTotalMoney()->toString();
    sprintf(totalMoneyStr,"%s", deltotalMoney);
    delete[] deltotalMoney;
    
    char* delTouchNumbers = this->counter->getTouchNumbers()->toString();
    sprintf(touchNumbersStr,"%s", delTouchNumbers);
    delete[] delTouchNumbers;
    
    sprintf(timePlayStr,"%f",this->counter->getTimePlay());
    
    char* delTouchMoney = this->counter->getTouchMoney()->toString();
    sprintf(touchMoneyStr,"%s", delTouchMoney);
    delete[]delTouchMoney;
    
    counterStr.append("{\"totalMoney\":\"");
    counterStr.append(totalMoneyStr);
    counterStr.append("\",\"touchNumbers\":\"");
    counterStr.append(touchNumbersStr);
    counterStr.append("\",\"touchMoney\":\"");
    counterStr.append(touchMoneyStr);
    counterStr.append("\",\"timePlay\":");
    counterStr.append(timePlayStr);
    counterStr.append("}");
    Utils::writeFile(counterStr,DOC_COUNTER, true);
}

void GameModel::saveStatusAchievement() {
    string achievementStr;
    achievementStr.append("{\"achievements\": [");
    for (int i = 0; i < this->achievements->count(); i++ ) {
        AbstractAchievement* achievement = (AbstractAchievement*) this->achievements->getObjectAtIndex(i);
        char status[5];
        sprintf(status, "%d", achievement->getStatus());
        achievementStr.append(status);
        if (i != this->achievements->count() - 1) {
            achievementStr.append(",\n");
        }
    }
    achievementStr.append("]}");
    Utils::writeFile(achievementStr, DOC_STATUS_ACHIEVEMENT, true);
}

void GameModel::loadStatusAchievement() {
    Json* root;
    string fileData = Utils::readFile(DOC_STATUS_ACHIEVEMENT, true, false, true);
    root = Json_create(fileData.data());
    if (root){
        Json* achievements = Json_getItem(root, "achievements");
        int achievementSize = achievements->size;
        for (int i = 0; i < achievementSize; i++) {
            AbstractAchievement* achievement = (AbstractAchievement*) this->achievements->getObjectAtIndex(i);
            Json* status = Json_getItemAt(achievements, i);
            int statusInteger = status->valueInt;
            achievement->setStatus(statusInteger);
        }
    }
}
int GameModel::getTotalCharactersLevel() {
    int totalLevel = 0;
    for(int i=0;i<this->characters->count();i++)
    {
        Character* character = (Character*)this->characters->objectForKey(i);
        totalLevel+= character->getLevel();
    }
    return totalLevel;
}

int GameModel::getTotalCharactersUpgrade() {
    int totalUpgradeLevel = 0;
    for(int i=0;i<this->characters->count();i++)
    {
        Character* character = (Character*)this->characters->objectForKey(i);
        totalUpgradeLevel+= character->getUpgradeLevel();
    }
    totalUpgradeLevel+= this->finger->getUpgradeLevel();
    return totalUpgradeLevel;
}

BigNumber* GameModel::bonusFinger(BigNumber* money)
{
    BigNumber* bonusNumber = BigNumber::create();
    bonusNumber->initialize(0);
    for(int i=0;i<this->finger->getBonusLevel();i++)
    {
        FingerBonus* fingerBonus = (FingerBonus*)this->fingerInformation->getBonusInfo()->getObjectAtIndex(i);
        BigNumber* eachBonusNumber = money->multiplyRationalNumber(fingerBonus->getPercent());
        bonusNumber = bonusNumber->add(eachBonusNumber);
    }
    return bonusNumber;
}

BigNumber* GameModel::bonusAtm(BigNumber* money) {
    this->counter->setTotalBonusPercentATM(0.0f);
    for(int i = 0; i <= this->atm->getBonusLevel(); i++) {
        AtmBonus* bonus = (AtmBonus*)this->atmInformation->getBonusInfo()->getObjectAtIndex(i);
        
        this->counter->setTotalBonusPercentATM(this->counter->getTotalBonusPercentATM() + bonus->getMultiplierPercent());
        
    }
    float percent = (float)this->counter->getTotalBonusPercentATM() / 100;
    BigNumber* bonusNumber = money->multiplyRationalNumber(percent);
    money = money->add(bonusNumber);
    return money;
}

BigNumber* GameModel::achievementEffect(BigNumber* money, int effectType) {
    float totalPercent = 0.0f;
    for(int i = 0; i < this->achievements->count(); i++) {
        AbstractAchievement* achievement = (AbstractAchievement*) this->achievements->getObjectAtIndex(i);
        if (achievement->getStatus() == NUM_STATUS_UNLOCKED) {
            if (achievement->getEffectType() == ACHIEVEMENT_EFFECT_DPS && effectType == ACHIEVEMENT_EFFECT_DPS) {
                totalPercent += achievement->getEffectPercent();
            } else if (achievement->getEffectType() == ACHIEVEMENT_EFFECT_GRANDMA && effectType == ACHIEVEMENT_EFFECT_GRANDMA) {
                totalPercent += 20 * achievement->getEffectPercent();
            } else if (achievement->getEffectType() == ACHIEVEMENT_EFFECT_GAMEDEV && effectType == ACHIEVEMENT_EFFECT_GAMEDEV) {
                totalPercent += achievement->getEffectPercent();
            }
        }
    }
    BigNumber* bonusNumber = money->multiplyRationalNumber(totalPercent);
    money = money->add(bonusNumber);
    return money;
}
void GameModel::setComparisonAchievement() {
    for(int i = 0; i < this->achievements->count(); i++){
        AbstractAchievement* achievement = (AbstractAchievement*)achievements->getObjectAtIndex(i);
        if(achievement->getType() == ACHIEVEMENT_TYPE_MONEY) //MONEY ACHIEVEMENT
        {
            MoneyAchievement* element = (MoneyAchievement*) achievement;
            int id = element->getAchievementID();
            switch(id){
                case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
                case 8:case 9:case 10:case 11:case 12:case 13:case 14:
                case 15:
                {
                    element->setComparedNumber(this->counter->getTotalMoney()); break;
                }
                case 16: case 17: case 18: case 19: case 20: case 21:
                case 22: case 23: case 24: case 25:
                {
                    element->setComparedNumber(this->counter->getTotalSpeed()); break;
                }
                case 26: case 27: case 28: case 29: case 30: case 31:
                case 32:
                {
                    element->setComparedNumber(this->counter->getTouchMoney()); break;
                }
                case 39:
                {
                    Character* character1 = (Character*) characters->objectForKey(CHAR_GRANDMA);
                    element->setComparedNumber(character1->getCharacterMoney());
                    break;
                }
                case 45:
                {
                    Character* character2 = (Character*) characters->objectForKey(CHAR_KID);
                    element->setComparedNumber(character2->getCharacterMoney());
                    break;
                }
                case 51:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_CEO);
                    element->setComparedNumber(character3->getCharacterMoney());
                    break;
                }
                case 57:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_GOVERMENT);
                    element->setComparedNumber(character3->getCharacterMoney());
                    break;
                }
                case 63:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_HACKER);
                    element->setComparedNumber(character3->getCharacterMoney());
                    break;
                }
                case 69:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_SUPER_MAN);
                    element->setComparedNumber(character3->getCharacterMoney());
                    break;
                }
                case 75:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_GHOST);
                    element->setComparedNumber(character3->getCharacterMoney());
                    break;
                }
                case 81:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_GOD);
                    element->setComparedNumber(character3->getCharacterMoney());
                    break;
                }
                case 99:
                {
                    Character* character = (Character*) characters->objectForKey(CHAR_GAME_DEV);
                    element->setComparedNumber(character->getCharacterMoney());
                    break;
                }
            }
        }
        if(achievement->getType() == ACHIEVEMENT_TYPE_LEVEL)
        {
            LevelAchievement* element = (LevelAchievement*) achievement;
            int id = element->getAchievementID();
            switch(id){
                case 33: case 34: case 35: case 36: case 37: case 38:
                {
                    Character* character1 = (Character*) characters->objectForKey(CHAR_GRANDMA);
                    element->setComparedLevel(character1->getLevel());
                    break;
                }
                case 40: case 41: case 42: case 43: case 44:
                {
                    Character* character2 = (Character*) characters->objectForKey(CHAR_KID);
                    element->setComparedLevel(character2->getLevel());
                    break;
                }
                case 46: case 47: case 48: case 49: case 50:
                {
                    Character* character3 = (Character*) characters->objectForKey(CHAR_CEO);
                    element->setComparedLevel(character3->getLevel());
                    break;
                }
                case 52: case 53: case 54: case 55: case 56:
                {
                    Character* character4 = (Character*) characters->objectForKey(CHAR_GOVERMENT);
                    element->setComparedLevel(character4->getLevel());
                    break;
                }
                case 58: case 59: case 60: case 61: case 62:
                {
                    Character* character5 = (Character*) characters->objectForKey(CHAR_HACKER);
                    element->setComparedLevel(character5->getLevel());
                    break;
                }
                case 64: case 65: case 66: case 67: case 68:
                {
                    Character* character6 = (Character*) characters->objectForKey(CHAR_SUPER_MAN);
                    element->setComparedLevel(character6->getLevel());
                    break;
                }
                case 70: case 71: case 72: case 73: case 74:
                {
                    Character* character7 = (Character*) characters->objectForKey(CHAR_GHOST);
                    element->setComparedLevel(character7->getLevel());
                    break;
                }
                case 76: case 77: case 78: case 79: case 80:
                {
                    Character* character7 = (Character*) characters->objectForKey(CHAR_GOD);
                    element->setComparedLevel(character7->getLevel());
                    break;
                }
                case 94: case 95: case 96: case 97: case 98:
                {
                    Character* character8 = (Character*) characters->objectForKey(CHAR_GAME_DEV);
                    element->setComparedLevel(character8->getLevel());
                    break;
                }
                case 82: case 83: case 84: case 85:
                {
                    element->setComparedLevel(this->getTotalCharactersLevel());
                    break;
                }
                case 86: case 87: case 88: case 89:
                {
                    element->setComparedLevel(this->getTotalCharactersUpgrade());
                    break;
                }
                    
            }
        }
        if(achievement->getType() == ACHIEVEMENT_TYPE_OTHER) {
            OtherAchievement* element = (OtherAchievement*) achievement;
            int id = element->getAchievementID();
            switch(id) {
                case 90: case 91: case 92: case 93:
                {
                    __Array* allKeys = this->getCharacters()->allKeys();
                    for (int i = 0; i < allKeys->count(); i++){
                        __Integer* key = (__Integer*) allKeys->getObjectAtIndex(i);
                        Character* character = (Character*) this->getCharacters()->objectForKey(key->getValue());
                        __Integer* level = __Integer::create(character->getLevel());
                        element->getComparedObjects()->setObject(level, key->getValue());
                    }
                    break;
                }
            }
        }
    }
}

void GameModel::examineAchievements(){
    int numOfUnlocked = 0;
    for(int i = 0; i < achievements->count(); i++){
        AbstractAchievement* achievement = (AbstractAchievement*)achievements->getObjectAtIndex(i);
        if(achievement->getStatus() == NUM_STATUS_LOCKED || achievement->getStatus() == NUM_STATUS_BOUGHT){
            bool test = achievement->examine();
            if (test == true){
                this->fireShowAchievementNoti(achievement->getAchievementID());
                this->saveStatusAchievement();
            }
            
        } else {
            numOfUnlocked++;
        }
    }
    this->numOfUnlockedAchi = numOfUnlocked;
}
